home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / PopupCDEF 1.0b3 / PopupCDEF.c < prev    next >
C/C++ Source or Header  |  1994-03-16  |  9KB  |  299 lines

  1. /* See the file Distribution for distribution terms.
  2.     (c) Copyright 1994 Ari Halberstadt */
  3.  
  4. /*    This file contains a popup CDEF that uses the file PopupLib.c to handle
  5.     the details of popup menus. This file contains glue to link the Control
  6.     Manager and the routines in PopupLib.c.
  7.  
  8.     94/03/15 aih
  9.     - Added check against kPopupVersion before a CDEF is attached during
  10.     debugging with PopupCDEFAttach.
  11.     - Moved description to documentation file.
  12.     - Uses bullet instead of check mark as mark character when using
  13.     window font.
  14.     - Added support for the popupFixedWidth variation code.
  15.     
  16.     94/01/19 aih
  17.     - Added call to GetMHandle to allow use of menus created by the application
  18.     that are not in the resource file. Also fixed use of an already disposed
  19.     handle in the CDEF's dispose routine. Thanks to Eric Bowman (bobo@reed.edu)
  20.     for both of these.
  21.      
  22.     93/12/31 aih
  23.     - Returns 1 as part code (same as 7.0 CDEF) instead of inCheckBox
  24.     
  25.     93/12/26 aih
  26.     - Major overhaul. Now supports most of the features of the System 7.0 CDEF.
  27.     - Added functions for installing a glue handle to the popup CDEF,
  28.     allowing the CDEF to be debugged from within an application. The only
  29.     message that can't be debugged this way is the initCntl message,
  30.     since initCntl is sent by NewControl before we can install the
  31.     glue handle.
  32.     
  33.     93/12/24 aih
  34.     - Adapted to use PopupHandle type
  35.     - Removed dependence on other libraries
  36.     - Simplified by removing complicated variation setting code
  37.     based on parsing the title string
  38.     
  39.     91/03/15 aih
  40.     - Fixed bug which caused a crash if the menu resource specified in the
  41.     control's refCon field couldn't be loaded
  42.     
  43.     91/03/04-05 Ari Halberstadt (aih)
  44.     - Created this file */
  45.     
  46. #include <limits.h>
  47. #include <LoMem.h>
  48. #include <SetUpA4.h>
  49. #include "PopupLib.h"
  50.  
  51. /* mask for the low 31 bits of the calcCRgns message to CDEFs */
  52. #define calcCRgnsMask        (0x7fffffffL)
  53.  
  54. /* hilite value for a disabled control */
  55. #define kControlDisabled    (255)
  56.  
  57. /* System software version needed to use this CDEF. Tested with system 6.0.5
  58.     and 7.0, but may work on systems as early as 4.0.1. */
  59. #define kSystemVersion        (0x0605)
  60.  
  61. /* The checkMark character is only present in the Chicago system font,
  62.     whereas the bullet character ('•') is present in most fonts. When the
  63.     popupUseWFont variation code is used, we change the mark character
  64.     from the default checkMark to kBulletMark. */
  65. #define kBulletMark            ('•')
  66.  
  67. /* draw the control */
  68. static void Draw(ControlHandle ctl, PopupHandle popup)
  69. {
  70.     Str255 title;
  71.     Rect bounds;
  72.     
  73.     GetCTitle(ctl, title);
  74.     bounds = (**ctl).contrlRect;
  75.     PopupDrawSet(popup, false);
  76.     PopupTitleSet(popup, title);
  77.     PopupBoundsSet(popup, &bounds);
  78.     PopupVisibleSet(popup, (**ctl).contrlVis);
  79.     PopupCurrentSet(popup, (**ctl).contrlValue);
  80.     PopupEnableSet(popup, (**ctl).contrlHilite != kControlDisabled);
  81.     PopupDrawSet(popup, true);
  82.     PopupCalculate(popup);
  83.     PopupDraw(popup);
  84. }
  85.  
  86. /* return the part of the control that the point is in */
  87. static long Test(ControlHandle ctl, PopupHandle popup, Point where)
  88. {
  89.     return(PopupWithin(popup, where) ? kPopupPartCode : 0);
  90. }
  91.  
  92. /* calculate the region containing the control */
  93. static void Calculate(ControlHandle ctl, PopupHandle popup, RgnHandle rgn)
  94. {
  95.     Rect bounds;
  96.     
  97.     PopupBounds(popup, &bounds);
  98.     RectRgn(rgn, &bounds);
  99. }
  100.  
  101. /* load the menu and set 'gotmenu' to true if we called GetMenu */
  102. static MenuHandle LoadMenu(short id, Boolean *gotmenu)
  103. {
  104.     MenuHandle    menu;        /* the menu */
  105.     ProcPtr        errproc;    /* for saving and restoring ResErrProc */
  106.     short            load;        /* for saving and restoring ResLoad */
  107.     
  108.     /* we can tell if the menu hasn't been loaded by a call to GetMenu
  109.         since the menu handle will be a nil resource handle */
  110.     *gotmenu = false;
  111.     load = ResLoad;
  112.     SetResLoad(false);
  113.     menu = (MenuHandle) GetResource('MENU', id);
  114.     SetResLoad(load);
  115.     if (menu && ! *menu) {
  116.         /* The menu is in the resource file, but it hasn't been loaded
  117.             yet, so we have to call GetMenu. */
  118.         errproc = ResErrProc;
  119.         ResErrProc = NULL;
  120.         menu = GetMenu(id);
  121.         ResErrProc = errproc;
  122.         *gotmenu = true;
  123.     }
  124.     else if (! menu) {
  125.         /* To allow use of menus created by the application that are not in the
  126.             resource file we look for the menu in the menu list. */
  127.         menu = GetMHandle(id);
  128.     }
  129.     return(menu);
  130. }
  131.  
  132. /* initialize the control */
  133. static void Initialize(ControlHandle ctl, short var)
  134. {
  135.     MenuHandle    menu;        /* the menu */
  136.     PopupHandle popup;    /* handle to the popup menu */
  137.     Rect            bounds;    /* control's bounding rectangle */
  138.     short            nitems;    /* number of items in menu */
  139.     Boolean        gotmenu;    /* true if we created the menu by calling GetMenu */
  140.     
  141.     menu = LoadMenu((**ctl).contrlMin, &gotmenu);
  142.     if (menu) {
  143.         if (gotmenu && (var & popupUseAddResMenu) != 0)
  144.             AddResMenu(menu, (**ctl).contrlRfCon);
  145.         bounds = (**ctl).contrlRect;
  146.         popup = PopupBegin((**ctl).contrlOwner, menu, &bounds);
  147.         if (popup) {
  148.             (**popup).state.gotmenu = gotmenu;
  149.             PopupDrawSet(popup, false);
  150.             PopupTitleWidthSet(popup, (**ctl).contrlMax);
  151.             if (((**ctl).contrlValue & popupTitleNoStyle) == 0)
  152.                 PopupTitleStyleSet(popup, (**ctl).contrlValue >> CHAR_BIT);
  153.             if (((**ctl).contrlValue & popupTitleRightJust) == popupTitleRightJust)
  154.                 PopupJustSet(popup, teFlushRight);
  155.             if ((var & popupUseWFont) != 0)
  156.                 PopupMarkSet(popup, kBulletMark);
  157.             PopupTypeInSet(popup, (var & popupTypeIn) != 0);
  158.             PopupUseWFontSet(popup, (var & popupUseWFont) != 0);
  159.             PopupFixedWidthSet(popup, (var & popupFixedWidth) != 0);
  160.             PopupDrawSet(popup, true);
  161.             PopupCalculate(popup);
  162.             nitems = CountMItems(menu);
  163.             (**ctl).contrlMax = nitems;
  164.             (**ctl).contrlMin = (nitems > 0 ? 1 : 0);
  165.             (**ctl).contrlValue = (nitems > 0 ? 1 : 0);
  166.             (**ctl).contrlData = (Handle) popup;
  167.             (**ctl).contrlAction = (ProcPtr) -1L;
  168.         }
  169.     }
  170. }
  171.  
  172. /* dispose of the control */
  173. static void Dispose(ControlHandle ctl, PopupHandle popup)
  174. {
  175.     MenuHandle menu;
  176.     Boolean gotmenu;
  177.     
  178.     menu = (**popup).menu;
  179.     gotmenu = (**popup).state.gotmenu;
  180.     PopupEnd(popup);
  181.     if (gotmenu)
  182.         ReleaseResource((Handle) menu);
  183.     (**ctl).contrlData = NULL;
  184. }
  185.  
  186. /* track a mouse click in the control */
  187. static void Track(ControlHandle ctl, PopupHandle popup)
  188. {
  189.     short value;
  190.     
  191.     PopupSelect(popup);
  192.     value = PopupCurrent(popup);
  193.     (**ctl).contrlValue = value;
  194. }
  195.  
  196. /* entry point for CDEF */
  197. pascal long PopupCDEF(short var, ControlHandle ctl, short msg, long param)
  198. {
  199.     PopupHandle    popup = NULL;
  200.     SysEnvRec world;
  201.     long result = 0;
  202.     
  203.     /* setup global variables */
  204.     RememberA0();
  205.     SetUpA4();
  206.     
  207.     /* check system software */
  208.     (void) SysEnvirons(curSysEnvVers, &world);
  209.     if (world.systemVersion >= kSystemVersion) {
  210.         
  211.         /* execute message */
  212.         popup = (PopupHandle) (**ctl).contrlData;
  213.         if (msg == initCntl) {
  214.             Initialize(ctl, var);
  215.             popup = (PopupHandle) (**ctl).contrlData;
  216.         }
  217.         else if (popup) {
  218.             switch (msg) {
  219.             case drawCntl:
  220.                 param = LoWord(param); /* see TN196 */
  221.                 Draw(ctl, popup);
  222.                 break;
  223.             case testCntl:
  224.                 result = Test(ctl, popup, *(Point *) ¶m);
  225.                 break;
  226.             case calcCRgns:
  227.                 param &= calcCRgnsMask;
  228.                 /* no break */
  229.             case calcCntlRgn:
  230.             case calcThumbRgn:
  231.                 Calculate(ctl, popup, (RgnHandle) param);
  232.                 break;
  233.             case dispCntl:
  234.                 Dispose(ctl, popup);
  235.                 popup = NULL;
  236.                 break;
  237.             case autoTrack:
  238.                 param = LoWord(param); /* see TN196 */
  239.                 Track(ctl, popup);
  240.                 break;
  241.             }
  242.         }
  243.     }
  244.     RestoreA4();
  245.     return(result);
  246. }
  247.  
  248. #ifdef CDEF
  249. pascal long main(short var, ControlHandle ctl, short msg, long param)
  250. {
  251.     return(PopupCDEF(var, ctl, msg, param));
  252. }
  253. #endif /* CDEF */
  254.  
  255. #if ! CDEF && ! NDEBUG
  256.  
  257. /* Functions for attaching a glue handle so the CDEF can be debugged
  258.     from within an application. */
  259.     
  260. #define ASM_JMP (0x4EF9)    /* jump instruction */
  261.  
  262. /* the structure installed in the contrlDefProc field */
  263. typedef struct {
  264.     short jmp;                    /* jump instruction */
  265.     void *addr;                    /* address of CDEF function */
  266.     Handle contrlDefProc;    /* saved value of contrlDefProc field */
  267. } PopupGlueType, *PopupGluePtr, **PopupGlueHandle;
  268.  
  269. /* Set the control's defproc field to a small glue handle that will
  270.     jump to PopupCDEF. This makes debugging a lot easier, since you
  271.     can then step through the code with a debugger. */
  272. void PopupCDEFAttach(ControlHandle ctl)
  273. {
  274.     PopupGlueHandle glue;
  275.     
  276.     if (PopupVersion((PopupHandle) (**ctl).contrlData) == kPopupVersion) {
  277.         glue = (PopupGlueHandle) NewHandleClear(sizeof(PopupGlueType));
  278.         if (glue) {
  279.             (**glue).jmp = ASM_JMP;
  280.             (**glue).addr = PopupCDEF;
  281.             (**glue).contrlDefProc = (**ctl).contrlDefProc;
  282.             (**ctl).contrlDefProc = (Handle) glue;
  283.         }
  284.     }
  285. }
  286.  
  287. /* Dispose of the glue handle created with PopupCDEFAttach and set the
  288.     control's contrlDefProc field to point to its original value. */
  289. void PopupCDEFDetach(ControlHandle ctl)
  290. {
  291.     PopupGlueHandle glue;
  292.     
  293.     glue = (PopupGlueHandle) (**ctl).contrlDefProc;
  294.     (**ctl).contrlDefProc = (**glue).contrlDefProc;
  295.     DisposeHandle((Handle) glue);
  296. }
  297.  
  298. #endif /* ! CDEF && ! NDEBUG */
  299.